home *** CD-ROM | disk | FTP | other *** search
/ Aminet 34 / Aminet 34 (2000)(Schatztruhe)[!][Dec 1999].iso / Aminet / util / gnu / unixcmds.lha / unixcmds / src / grep-2.1 / dosbuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-06  |  5.7 KB  |  185 lines

  1. /* Messy DOS-specific code for correctly treating binary, Unix text
  2.    and DOS text files.
  3.  
  4.    This has several aspects:
  5.  
  6.      * Guessing the file type (unless the user tells us);
  7.      * Stripping CR characters from DOS text files (otherwise regex
  8.        functions won't work correctly);
  9.      * Reporting correct byte count with -b for any kind of file.
  10.  
  11. */
  12.  
  13. typedef enum {
  14.   UNKNOWN, DOS_BINARY, DOS_TEXT, UNIX_TEXT
  15. } File_type;
  16.  
  17. struct dos_map {
  18.   size_t pos;       /* position in buffer passed to matcher */
  19.   int    add;       /* how much to add when reporting char position */
  20. };
  21.  
  22. static int       dos_report_unix_offset = 0;
  23.  
  24. static File_type dos_file_type     = UNKNOWN;
  25. static File_type dos_use_file_type = UNKNOWN;
  26. static size_t    dos_stripped_crs  = 0;
  27. static struct dos_map *dos_pos_map;
  28. static int       dos_pos_map_size  = 0;
  29. static int       dos_pos_map_used  = 0;
  30. static int       inp_map_idx = 0, out_map_idx = 1;
  31.  
  32. /* Guess DOS file type by looking at its contents.  */
  33. static inline File_type
  34. guess_type(char *buf, register size_t buflen)
  35. {
  36.   int crlf_seen = 0;
  37.   /* Use unsigned char, so this will work with foreign characters.  */
  38.   register unsigned char *bp = buf;
  39.  
  40.   while (buflen--)
  41.     {
  42.       /* Binary files have characters with ASCII code less then 32 decimal,
  43.          unless they are one of: BS (for man pages), TAB, LF, FF, CR, ^Z. */
  44.       if (*bp  < ' '  && !(*bp > '\a' && *bp <= '\n') &&
  45.           *bp != '\f' &&   *bp != '\r' && *bp != '\32')
  46.         return DOS_BINARY;
  47.  
  48.       /* CR before LF means DOS text file (unless we later see
  49.          binary characters).  */
  50.       else if (*bp == '\r' && bp[1] == '\n')
  51.         crlf_seen++;
  52.  
  53.       bp++;
  54.     }
  55.  
  56.   return crlf_seen ? DOS_TEXT : UNIX_TEXT;
  57. }
  58.  
  59. /* Convert external DOS file representation to internal.
  60.    Return the count of characters left in the buffer.
  61.    Build table to map character positions when reporting byte counts.  */
  62. static inline int
  63. undossify_input(register char *buf, size_t buflen)
  64. {
  65.   int chars_left = 0;
  66.  
  67.   if (totalcc == 0)
  68.     {
  69.       /* New file: forget everything we knew about character
  70.          position mapping table and file type.  */
  71.       inp_map_idx = 0;
  72.       out_map_idx = 1;
  73.       dos_pos_map_used = 0;
  74.       dos_stripped_crs = 0;
  75.       dos_file_type = dos_use_file_type;
  76.     }
  77.  
  78.   /* Guess if this file is binary, unless we already know that.  */
  79.   if (dos_file_type == UNKNOWN)
  80.     dos_file_type = guess_type(buf, buflen);
  81.  
  82.   /* If this file is to be treated as DOS Text, strip the CR characters
  83.      and maybe build the table for character position mapping on output.  */
  84.   if (dos_file_type == DOS_TEXT)
  85.     {
  86.       char   *destp   = buf;
  87.  
  88.       while (buflen--)
  89.         {
  90.           if (*buf != '\r')
  91.             {
  92.               *destp++ = *buf++;
  93.               chars_left++;
  94.             }
  95.           else
  96.             {
  97.               buf++;
  98.               if (out_byte && !dos_report_unix_offset)
  99.                 {
  100.                   dos_stripped_crs++;
  101.                   while (buflen && *buf == '\r')
  102.                     {
  103.                       dos_stripped_crs++;
  104.                       buflen--;
  105.                       buf++;
  106.                     }
  107.                   if (inp_map_idx >= dos_pos_map_size - 1)
  108.                     {
  109.                       dos_pos_map_size = inp_map_idx ? inp_map_idx * 2 : 1000;
  110.                       dos_pos_map =
  111.                         (struct dos_map *)xrealloc((char *)dos_pos_map,
  112.                            dos_pos_map_size *
  113.                            sizeof(struct dos_map));
  114.                     }
  115.  
  116.                   if (!inp_map_idx)
  117.                     {
  118.                       /* Add sentinel entry.  */
  119.                       dos_pos_map[inp_map_idx].pos = 0;
  120.                       dos_pos_map[inp_map_idx++].add = 0;
  121.  
  122.                       /* Initialize first real entry.  */
  123.                       dos_pos_map[inp_map_idx].add = 0;
  124.                     }
  125.  
  126.                   /* Put the new entry.  If the stripped CR characters
  127.                      preceed a Newline (the usual case), pretend that
  128.                      they were found *after* the Newline.  This makes
  129.                      displayed byte offsets more reasonable in some
  130.                      cases, and fits better the intuitive notion that
  131.                      the line ends *before* the CR, not *after* it.  */
  132.                   inp_map_idx++;
  133.                   dos_pos_map[inp_map_idx-1].pos =
  134.                     (*buf == '\n' ? destp + 1 : destp ) - bufbeg + totalcc;
  135.                   dos_pos_map[inp_map_idx].add = dos_stripped_crs;
  136.                   dos_pos_map_used = inp_map_idx;
  137.  
  138.                   /* The following will be updated on the next pass.  */
  139.                   dos_pos_map[inp_map_idx].pos = destp - bufbeg + totalcc + 1;
  140.                 }
  141.             }
  142.         }
  143.  
  144.       return chars_left;
  145.     }
  146.  
  147.   return buflen;
  148. }
  149.  
  150. /* Convert internal byte count into external.  */
  151. static inline size_t
  152. dossified_pos(size_t byteno)
  153. {
  154.   size_t pos_lo;
  155.   size_t pos_hi;
  156.  
  157.   if (dos_file_type != DOS_TEXT || dos_report_unix_offset)
  158.     return byteno;
  159.  
  160.   /* Optimization: usually the file will be scanned sequentially.
  161.      So in most cases, this byte position will be found in the
  162.      table near the previous one, as recorded in `out_map_idx'.  */
  163.   pos_lo = dos_pos_map[out_map_idx-1].pos;
  164.   pos_hi = dos_pos_map[out_map_idx].pos;
  165.  
  166.   /* If the initial guess failed, search up or down, as
  167.      appropriate, beginning with the previous place.  */
  168.   if (byteno >= pos_hi)
  169.     {
  170.       out_map_idx++;
  171.       while (out_map_idx < dos_pos_map_used &&
  172.              byteno >= dos_pos_map[out_map_idx].pos)
  173.         out_map_idx++;
  174.     }
  175.  
  176.   else if (byteno < pos_lo)
  177.     {
  178.       out_map_idx--;
  179.       while (out_map_idx > 1 && byteno < dos_pos_map[out_map_idx-1].pos)
  180.         out_map_idx--;
  181.     }
  182.  
  183.   return byteno + dos_pos_map[out_map_idx].add;
  184. }
  185.